package com.boarsoft.boar.batch.action;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.boarsoft.boar.batch.biz.BatchExecutionBiz;
import com.boarsoft.boar.batch.biz.BatchInfoBiz;
import com.boarsoft.boar.batch.entity.BatchExecution;
import com.boarsoft.boar.batch.entity.BatchInfo;
import com.boarsoft.boar.batch.service.BatchDispatcher;
import com.boarsoft.boar.common.Constants;
import com.boarsoft.common.Authorized;
import com.boarsoft.common.Util;
import com.boarsoft.common.action.PageAction;
import com.boarsoft.common.dao.PagedResult;
import com.boarsoft.common.util.BeanUtil;
import com.boarsoft.common.util.JsonUtil;

@SuppressWarnings("serial")
@Component
@Scope("prototype")
@ParentPackage("default-package")
@Namespace(value = "/execution")
public class BatchExecutionAction extends PageAction implements ApplicationContextAware {

	@Autowired
	private BatchExecutionBiz batchExeBiz;
	@Autowired
	private BatchInfoBiz batchInfoBiz;

	private String id;

	private String infoId;

	private String key;

	private boolean force;
	
	private String keys;

	private ApplicationContext applicationContext;

	private BatchDispatcher getBatchDispatcher() {
		BatchExecution be = batchExeBiz.get(id);
		if (be == null) {
			writeReply(BatchExecution.ERROR_NOT_FOUND);
			return null;
		}
		BatchInfo bi = null;
		if (Util.strIsNotEmpty(be.getInfoId())) {
			bi = batchInfoBiz.get(be.getInfoId());
		}
		if (bi == null) {
			writeReply(BatchExecution.ERROR_MISSING_INFO);
			return null;
		}
		BatchDispatcher bd = null;
		if (Util.strIsNotEmpty(bi.getImpl())) {
			if (applicationContext.containsBean(bi.getImpl())) {
				bd = (BatchDispatcher) applicationContext.getBean(bi.getImpl());
			}
		}
		if (bd == null) {
			writeReply(Constants.ERROR_INVALID, "impl");
			return null;
		}
		return bd;
	}

	@Action("resume")
	@Authorized(code = "batch.execution.resume")
	public void resume() {
		if (Util.strIsEmpty(id)) {
			writeReply(Constants.ERROR_INVALID, "resume");
			return;
		}
		BatchDispatcher bd = this.getBatchDispatcher();
		if (bd != null) {
			writeReply(bd.resume(id));
		}
	}

	@Action("redo")
	@Authorized(code = "batch.execution.redo")
	public void redo() {
		if (Util.strIsEmpty(id)) {
			writeReply(Constants.ERROR_INVALID, "redo");
			return;
		}
		BatchDispatcher bd = this.getBatchDispatcher();
		if (bd != null) {
			writeReply(bd.redo(id));
		}
	}

	@Action("cancel")
	@Authorized(code = "batch.execution.cancel")
	public void cancel() {
		if (Util.strIsEmpty(id)) {
			writeReply(Constants.ERROR_INVALID, "cancel");
			return;
		}
		BatchDispatcher bd = this.getBatchDispatcher();
		if (bd != null) {
			writeReply(bd.cancel(id, force));
		}
	}

	private void writeReply(int r) {
		switch (r) {
		case 0:
			writeReply();
			break;
		case BatchExecution.ERROR_NOT_FOUND:
			writeReply(Constants.ERROR_NOTFOUND, "execution");
			break;
		case BatchExecution.ERROR_MISSING_INFO:
			writeReply(Constants.ERROR_NOTFOUND, "info");
			break;
		case BatchExecution.ERROR_WRONG_STATUS:
			writeReply(Constants.ERROR_INVALID, "status");
			break;
		default:
			writeReply(Constants.ERROR_UNKNOWN);
			break;
		}
	}

	@Action("delete")
	@Authorized(code = "batch.execution.delete")
	public void delete() {
		if (Util.strIsEmpty(id)) {
			writeReply(Constants.ERROR_INVALID, "delete");
			return;
		}
		batchExeBiz.delete(id);
		writeReply();
	}

	@Action("list")
	@Authorized(code = "batch.execution.list")
	public void list() {
		PagedResult<BatchExecution> pr = batchExeBiz.list(infoId, key, orderBy, pageNo, pageSize);
		writeReply(true, JsonUtil.from(pr));
	}
	
	@Action("get")
	@Authorized(code = "batch.execution.get")
	public void get() {
		if (Util.strIsEmpty(id)) {
			writeReply(Constants.ERROR_INVALID, "get");
			return;
		}
		BatchExecution o = batchExeBiz.get(id);
		writeReply(true, JsonUtil.from(o));
	}
	
	@Action("refresh")
	@Authorized(code = "batch.execution.list")
	public void refresh() {
		if (Util.strIsEmpty(keys)) {
			writeReply(Constants.ERROR_INVALID, "refresh");
			return;
		}
		String[] ids = keys.trim().split(",");
		List<BatchExecution> list = batchExeBiz.list(ids);
		writeReply(true, JsonUtil.from(list));
	}
	
	@Action("listExecuting")
	@Authorized(code = "batch.execution.list")
	public void listExecuting() {
		PagedResult<Object[]> oPr = batchExeBiz.listExecuting(pageNo, pageSize);
		List<Object[]> oLt = oPr.getList();
		List<Map<String, Object>> rLt = new ArrayList<Map<String, Object>>(oLt.size());  
		for(Object[] oa : oLt){
			BatchExecution exe = (BatchExecution)oa[0];
			BatchInfo info = (BatchInfo)oa[1];
			Map<String, Object> map = new HashMap<String, Object>();
			BeanUtil.fillMapWithObject(map, exe);
			map.put("name", info.getName());
			rLt.add(map);
		}
		PagedResult<Map<String, Object>> rPr = new PagedResult<>(oPr.getTotal(), rLt, pageNo, pageSize);
		writeReply(true, JsonUtil.from(rPr));
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getKey() {
		return key;
	}

	public void setKey(String key) {
		this.key = key;
	}

	public String getInfoId() {
		return infoId;
	}

	public void setInfoId(String infoId) {
		this.infoId = infoId;
	}

	public BatchExecutionBiz getBatchExeBiz() {
		return batchExeBiz;
	}

	public void setBatchExeBiz(BatchExecutionBiz batchExeBiz) {
		this.batchExeBiz = batchExeBiz;
	}

	public boolean isForce() {
		return force;
	}

	public void setForce(boolean force) {
		this.force = force;
	}

	public String getKeys() {
		return keys;
	}

	public void setKeys(String keys) {
		this.keys = keys;
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}
}
